"""
函数的参数可以使用*分隔，*前面的参数是位置参数，*后面的参数是命名关键字参数
位置参数在传参时只需要对号入座即可，命名关键字参数必须用 参数名=参数值 的形式传参

21点游戏
"""
import random

from example03 import Poker, Player


class BlackJackPlayer(Player):
    """21点游戏玩家"""

    def __init__(self, name, *, money=0, is_banker=False):
        self.money = money
        self.is_banker = is_banker
        super().__init__(name)

    def win(self, curr_stake):
        """获胜"""
        self.money += 2 * curr_stake if self.current_point == 21 else curr_stake

    def lose(self, curr_stake):
        """失败"""
        self.money -= curr_stake

    @property
    def current_point(self):
        """玩家手上牌的点数"""
        sorted_cards = sorted(self.cards, key=lambda curr_card: curr_card.face, reverse=True)
        total = 0
        for card in sorted_cards:
            if card.face >= 10:
                total += 10
            elif card.face > 1:
                total += card.face
            else:
                total += 1 if total + 11 > 21 else 11
        return total


def reset_game(poker, players):
    """重新开始一局游戏"""
    # 玩家先扔掉手上的牌
    for player in players:
        player.throw_cards()
    # 重新洗牌
    poker.shuffle()
    # 每个玩家重新发两张牌
    for _ in range(2):
        for player in players:
            player.get_one(poker.deal())
    # 显示玩家手上的牌（暗牌和明牌）
    for player in players:
        display_cards(player, show_all=False)


def display_cards(player, *, show_all=True):
    """显示玩家手上的牌"""
    print(f'{player.name}：')
    # show_all为False时，不显示暗牌只显示明牌
    for index, card in enumerate(player.cards):
        if index == 0 and player.is_banker and not show_all:
            print('■', end=' ')
        else:
            print(card, end=' ')
    # show_all为True时，要显示玩家手上牌的点数
    print(f'{player.current_point}点' if show_all else '')


def main():
    poker = Poker()
    player1 = BlackJackPlayer('骆昊', money=1000)
    player2 = BlackJackPlayer('电脑', is_banker=True)
    while player1.money > 0:
        print(f'玩家{player1.name}总资产为：{player1.money}')
        # 当前下注的金额
        curr_stake = 0
        while curr_stake <= 0 or curr_stake > player1.money:
            curr_stake = int(input('请下注: '))
        # 重新开始一局游戏
        reset_game(poker, (player1, player2))
        # 是否爆炸（牌的点数超过21点）
        blow_up = False
        while True:
            choice = input('要牌吗？')
            if choice.lower() in ('y', 'yes', 'yeah'):
                player1.get_one(poker.deal())
                display_cards(player1, show_all=False)
                if player1.current_point > 21:
                    blow_up = True
                    print(f'玩家{player1.name}爆炸了')
                    player1.lose(curr_stake)
                    break
            else:
                break
        # 如果玩家没有爆炸就轮到庄家要牌
        if not blow_up:
            # 设定一个随机的最低点数期望值
            min_expected_point = 15 + random.randint(0, 4)
            # 如果手上的牌点数没有达到最低期望值就继续要牌
            while player2.current_point < min_expected_point:
                player2.get_one(poker.deal())
                if player2.current_point > 21:
                    blow_up = True
                    print(f'庄家{player2.name}爆炸了')
                    display_cards(player2)
                    player1.win(curr_stake)
                    break
        # 如果玩家和庄家都没有爆炸就比大小
        if not blow_up:
            display_cards(player1)
            display_cards(player2)
            # 玩家点数大于庄家点数玩家胜，点数相同或低于庄家点数庄家胜
            if player1.current_point > player2.current_point:
                player1.win(curr_stake)
            else:
                player1.lose(curr_stake)
    print('你破产了，游戏结束！')


if __name__ == '__main__':
    main()
